home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 476-500 / disk_500 / wiconify / wiconify-source.lzh / Source / wLayout.c < prev    next >
C/C++ Source or Header  |  1991-04-19  |  11KB  |  396 lines

  1. /*
  2.  *  WICONIFY    A utility that allows you to iconify any Intuition window
  3.  *              on any screen, and to open WB windows on any screen.
  4.  *
  5.  *  wLayout.c   Handles placement and rearranging of icons.
  6.  *
  7.  *  Copyright 1990 by Davide P. Cervone, all rights reserved.
  8.  *  You may use this code, provided this copyright notice is kept intact.
  9.  */
  10.  
  11. #include "wHandler.h"
  12.  
  13. static UWORD Xmax;                      /* maximum number of columns */
  14. static UWORD Ymax;                      /* maximum number of rows */
  15.  
  16. #define XOFFSET     80                  /* distance between icons */
  17. #define YOFFSET     34                  /* distance between icons */
  18. #define XSTART      20                  /* Starting X position */
  19. #define YSTART      28                  /* Starting Y position (from bottom) */
  20. #define YDIFF       10                  /* vertical offset for odd rows */
  21. #define XMAX        32                  /* maximum icons in x direction */
  22. #define YMAX        32                  /* maximum icons in y direction */
  23.  
  24. #define GADGICON        ((WICONREF *)theGadget->UserData)
  25.  
  26.  
  27. /*
  28.  *  GetPosition()
  29.  *
  30.  *  Get the icon of the gadget (UserData points to the icon)
  31.  *  Get the X position of the gadget normalized for varrying widths of icons
  32.  *  Find the nearest X column position by dividing by the column width
  33.  *  Get the Y position of the gadget normalized by height,with 0 at the bottom
  34.  *  Offset the Y position for odd rows
  35.  *  Get two different Y row positions (it may cover two positions vertically
  36.  *    if it is not exactly placed on the grid)
  37.  */
  38.  
  39. static void GetPosition(theGadget,X,Y1,Y2)
  40. struct Gadget *theGadget;
  41. WORD *X,*Y1,*Y2;
  42. {
  43.    WICONREF *theIcon = (WICONREF *)theGadget->UserData;
  44.  
  45.    *X  = theGadget->LeftEdge + (theGadget->Width - ICONWIDTH) / 2;
  46.    *X  = (*X - XSTART + (XOFFSET/2)) / XOFFSET;
  47.    *Y2 = theIcon->Screen->BackDrop->Height - theGadget->TopEdge;
  48.    *Y2 = *Y2 - (theGadget->Height - ICONHEIGHT) - YSTART;
  49.    if ((*X & 1) == 0) *Y2 -= YDIFF;
  50.    *Y1 = (*Y2 + (YOFFSET  /4)) / YOFFSET;
  51.    *Y2 = (*Y2 + (YOFFSET*3/4)) / YOFFSET;
  52. }
  53.  
  54.  
  55. /*
  56.  *  GetPositionArray()
  57.  *
  58.  *  Calculate the maximum number of rows and columns, clip to the array size
  59.  *  Clear the position array
  60.  *  While there are gadgets to work with
  61.  *    Get the gadget's position
  62.  *    Add it into the array
  63.  *    Add its second position into the array unless we are only conncered
  64.  *      with where the gadgets "should" be (ie, snapped to the grid)
  65.  *    Increment the gadget count if the gadget can be moved
  66.  *    Go on to the next gadget
  67.  *  Return the number of gadgets counted
  68.  */
  69.  
  70. static UWORD GetPositionArray(PosArray,theScreen,Snapped)
  71. ULONG PosArray[];
  72. WSCREEN *theScreen;
  73. int Snapped;
  74. {
  75.    struct Gadget *theGadget = theScreen->BackDrop->FirstGadget;
  76.    WORD X,Y1,Y2;
  77.    UWORD count = 0;
  78.    
  79.    Xmax = (theScreen->BackDrop->Width / XOFFSET);
  80.    Ymax = (theScreen->BackDrop->Height - YSTART) / YOFFSET;
  81.    if (Xmax > XMAX) Xmax = XMAX;
  82.    if (Ymax > YMAX) Ymax = YMAX;
  83.  
  84.    for (Y1 = 0; Y1 < YMAX; Y1++) PosArray[Y1] = 0;
  85.  
  86.    while(theGadget)
  87.    {
  88.       GetPosition(theGadget,&X,&Y1,&Y2);
  89.       PosArray[Y1] |= (1 << X);
  90.       if (Snapped == FALSE) PosArray[Y2] |= (1 << X);
  91.       if ((GADGICON->Icon.Flags & (WI_NOORGANIZE | WI_LOCKED)) == 0) count++;
  92.       theGadget = theGadget->NextGadget;
  93.    }
  94.    return(count);
  95. }
  96.  
  97.  
  98. /*
  99.  *  ValidPosition()
  100.  *
  101.  *  Check the row and column position to make sure it is on screen
  102.  *  If not, move it one the screen area
  103.  */
  104.  
  105. static void ValidPosition(X,Y)
  106. WORD *X,*Y;
  107. {
  108.    if (*X < 0) *X = 0;
  109.    if (*Y < 0) *Y = 0;
  110.    if (*X >= Xmax) *X = Xmax - 1;
  111.    if (*Y >  Ymax) *Y = Ymax;
  112. }
  113.  
  114. /*
  115.  *  Offsets for which positions to check when looking for the nearest
  116.  *  grid location (used when two icons overlap).  There are separate
  117.  *  choices for even and odd rows
  118.  */
  119.  
  120. #define DCOUNT  8
  121. static WORD dx[2][DCOUNT] =
  122. {
  123.    { 0, -1,  1, -1,  1, -1,  1,  0},
  124.    { 0, -1,  1, -1,  1,  0, -1,  1}
  125. };
  126.  
  127. static WORD dy[2][DCOUNT] =
  128. {
  129.    {-1,  0,  0, -1, -1,  1,  1,  1},
  130.    {-1, -1, -1,  0,  0,  1,  1,  1}
  131. };
  132.  
  133.  
  134. /*
  135.  *  FindClosePosition()
  136.  *
  137.  *  Check that the icon position is legal
  138.  *  If the gadget overlaps another one already in the array
  139.  *    Use the correct table for even or odd columns
  140.  *    While there are more positions to try
  141.  *      Get the new position for the given position
  142.  *      Make sure the position is within the screen
  143.  *      If the location is free
  144.  *        Save the new position and indicate that we're done
  145.  *  Indicate that the position is OK
  146.  *  Return a statment about whether there was a closeby place free
  147.  */
  148.  
  149. static int FindClosePosition(PosArray,X,Y,Y2)
  150. ULONG PosArray[];
  151. WORD *X,*Y,*Y2;
  152. {
  153.    int Found = FALSE;
  154.    short i,j;
  155.    WORD Xt,Yt;
  156.  
  157.    ValidPosition(X,Y);
  158.    if ((PosArray[*Y] | PosArray[*Y2]) & (1 << *X))
  159.    {
  160.       j = *X & 1;
  161.       for (i=0; i<DCOUNT && Found == FALSE; i++)
  162.       {
  163.          Xt = *X + dx[j][i];
  164.          Yt = *Y + dy[j][i];
  165.          ValidPosition(&Xt,&Yt);
  166.          if ((PosArray[Yt] & (1 << Xt)) == 0)
  167.          {
  168.             Found = TRUE;
  169.             *X = Xt; *Y = Yt;
  170.          }
  171.       }
  172.    } else Found = TRUE;
  173.    return(Found);
  174. }
  175.  
  176.  
  177. /*
  178.  *  GetNewPosition()
  179.  *
  180.  *  Create a mask with 1's in all the valid column positions
  181.  *  Look for the first row with an empty slot
  182.  *  If we are past the end of the array,
  183.  *    Set the position to the origin (bail out)
  184.  *  Otherwise
  185.  *    Look through the row from left to right for the first location
  186.  *  Verify that what we found really IS an OK position
  187.  */
  188.  
  189. static void GetNewPosition(PosArray,X,Y)
  190. ULONG PosArray[];
  191. WORD *X,*Y;
  192. {
  193.    ULONG Xmask = (1 << Xmax) - 1;
  194.  
  195.    for (*Y = 0; *Y < Ymax && (PosArray[*Y] & Xmask) == Xmask; (*Y)++);
  196.    if (*Y >= Ymax)
  197.       *Y = *X = 0;
  198.      else 
  199.       for (*X = 0, Xmask = 1; PosArray[*Y] & Xmask; (*X)++, Xmask <<= 1);
  200.    ValidPosition(X,Y);
  201. }
  202.  
  203.  
  204. /*
  205.  *  SetPosition()
  206.  *
  207.  *  If the icon is not locked in place
  208.  *    Get the current X and Y (in pixels) for the icon's new position
  209.  *      (centered the icon horizontally)
  210.  *    If the gadget's current location is different
  211.  *      Set the gadgets's new position
  212.  *      If the icon is supposed to get movement reports, report the change
  213.  */
  214.  
  215. static void SetPosition(theGadget,X,Y)
  216. struct Gadget *theGadget;
  217. WORD X,Y;
  218. {
  219.    WICONREF *theIcon = (WICONREF *)theGadget->UserData;
  220.  
  221.    if ((theIcon->Icon.Flags & WI_LOCKED) == FALSE)
  222.    {
  223.       Y  = theIcon->Screen->BackDrop->Height - YSTART - (Y * YOFFSET);
  224.       if ((X & 1) == 0) Y -= YDIFF;
  225.       X = (X * XOFFSET) + XSTART  - (theGadget->Width - ICONWIDTH) / 2;
  226.       Y -=  theGadget->Height - ICONHEIGHT;
  227.       if (theGadget->LeftEdge != X || theGadget->TopEdge != Y)
  228.       {
  229.          theGadget->LeftEdge = X; theIcon->Icon.x = X;
  230.          theGadget->TopEdge  = Y; theIcon->Icon.y = Y;
  231.          if (theIcon->Icon.Report & WI_REPORTMOVED)
  232.             ReportEvent(WI_REPORTMOVED,theIcon);
  233.       }
  234.    }
  235. }
  236.  
  237.  
  238. /*
  239.  *  InitPosition()
  240.  *
  241.  *  Get the position of the gadget and save it
  242.  *  Get the position array for the screen (do not snap icons to the grid)
  243.  *  If the gadget already has a position
  244.  *    If we can't find a closeby position get the first available one
  245.  *    If the position changed, set the new position
  246.  *  Otherwise
  247.  *    Get the first available position
  248.  *    Set the gadget's position
  249.  */
  250.  
  251. void InitPosition(theGadget)
  252. struct Gadget *theGadget;
  253. {
  254.    WICONREF *theIcon = (WICONREF *)theGadget->UserData;
  255.    ULONG PosArray[YMAX];
  256.    WORD X,Y,Y2;
  257.    WORD OldX,OldY;
  258.  
  259.    GetPosition(theGadget,&X,&Y,&Y2); OldX = X; OldY = Y;
  260.    GetPositionArray(PosArray,theIcon->Screen,FALSE);
  261.    if (theGadget->LeftEdge || theGadget->TopEdge)
  262.    {
  263.       if (!FindClosePosition(PosArray,&X,&Y,&Y2))
  264.          GetNewPosition(PosArray,&X,&Y);
  265.       if (X != OldX || Y != OldY) SetPosition(theGadget,X,Y);
  266.    } else {
  267.       GetNewPosition(PosArray,&X,&Y);
  268.       SetPosition(theGadget,X,Y);
  269.    }
  270. }
  271.  
  272.  
  273. /*
  274.  *  CleanUpIcons()
  275.  *
  276.  *  Get the positions of all icons on the screen (no snapping)
  277.  *  Clear the temporary array
  278.  *  Start with the first gadget on the screen
  279.  *  If there are selected gadgets
  280.  *    Add all the unselected gadgets to the temporary array
  281.  *    Start with the first selected gadget
  282.  *  While there are more gadgets to handle
  283.  *    Get the gadget's position and validate it
  284.  *    If the icon can be moved
  285.  *      If the icon's position is already in use
  286.  *        Find the closest place, or the next available one
  287.  *      Set the gadget's position
  288.  *    Add the gadget to the arrays
  289.  *    If gadgets are selected, go on to the next selected one
  290.  *    Otherwise go on to the next one
  291.  */
  292.  
  293. void CleanUpIcons(theScreen)
  294. WSCREEN *theScreen;
  295. {
  296.    ULONG PosArray[YMAX];
  297.    ULONG TmpArray[YMAX];
  298.    WORD  X,Y,Y2;
  299.    short Selected;
  300.    struct wGadget *theGadget;
  301.  
  302.    Forbid();
  303.  
  304.    GetPositionArray(PosArray,theScreen,FALSE);
  305.    for (Y = 0; Y < YMAX; Y++) TmpArray[Y] = 0;
  306.    theGadget = (struct wGadget *)theScreen->BackDrop->FirstGadget;
  307.    Selected = (theScreen->Selected != NULL);
  308.    if (Selected)
  309.    {
  310.       while (theGadget)
  311.       {
  312.          if ((theGadget->Gadget.Flags & SELECTED) == FALSE)
  313.          {
  314.             GetPosition(theGadget,&X,&Y,&Y2);
  315.             TmpArray[Y]  |= (1 << X);
  316.             TmpArray[Y2] |= (1 << X);
  317.          }
  318.          theGadget = (struct wGadget *)theGadget->Gadget.NextGadget;
  319.       }
  320.       theGadget = theScreen->Selected;
  321.    }
  322.    
  323.    while (theGadget)
  324.    {
  325.       GetPosition(theGadget,&X,&Y,&Y2);
  326.       ValidPosition(&X,&Y);
  327.       if ((GADGETICON->Icon.Flags & (WI_NOORGANIZE| WI_LOCKED)) == FALSE)
  328.       {
  329.          if ((TmpArray[Y] | TmpArray[Y2]) & (1 << X))
  330.             if (!FindClosePosition(PosArray,&X,&Y,&Y2))
  331.                GetNewPosition(PosArray,&X,&Y);
  332.          SetPosition(theGadget,X,Y);
  333.       }
  334.       TmpArray[Y] |= (1 << X);
  335.       PosArray[Y] |= (1 << X);
  336.       if (Selected)
  337.          theGadget = theGadget->NextSelect;
  338.         else
  339.          theGadget = (struct wGadget *)theGadget->Gadget.NextGadget;
  340.    }
  341.    Permit();
  342. }
  343.  
  344.  
  345. /*
  346.  *  OrganizeIcons()
  347.  *
  348.  *  Start with the first gadget on the screen
  349.  *  Count the gadgets and get the position array
  350.  *  Find the highest row and the right-most column in that row needed
  351.  *    in order to store that many icons
  352.  *  Clear the temporary array
  353.  *  While there are gadgets to check
  354.  *    Get the gadget's position and validate it
  355.  *    If the gadget can be moved
  356.  *      If the icon's position is in use, or if it is outside the final
  357.  *        block of organized icons, get a new position for the gadget
  358.  *      Set the gadgets position
  359.  *    Save the icon's position in both arrays
  360.  *    Move on to the next gadget
  361.  */
  362.  
  363. void OrganizeIcons(theScreen)
  364. WSCREEN *theScreen;
  365. {
  366.    ULONG PosArray[YMAX];
  367.    ULONG TmpArray[YMAX];
  368.    WORD  X,Y,Y2;
  369.    WORD  RightX, TopY;
  370.    UWORD count;
  371.    struct Gadget *theGadget;
  372.  
  373.    Forbid();
  374.    theGadget = theScreen->BackDrop->FirstGadget;
  375.    count = GetPositionArray(PosArray,theScreen,TRUE);
  376.    TopY = count / Xmax;
  377.    RightX = count - TopY * Xmax;
  378.    for (Y = 0; Y < YMAX; Y++) TmpArray[Y] = 0;
  379.    
  380.    while (theGadget)
  381.    {
  382.       GetPosition(theGadget,&X,&Y,&Y2);
  383.       ValidPosition(&X,&Y);
  384.       if ((GADGICON->Icon.Flags & (WI_NOORGANIZE| WI_LOCKED)) == FALSE)
  385.       {
  386.          if ((TmpArray[Y] & (1 << X)) || Y > TopY || (Y == TopY && X >= RightX))
  387.             GetNewPosition(PosArray,&X,&Y);
  388.          SetPosition(theGadget,X,Y);
  389.       }
  390.       PosArray[Y] |= (1 << X);
  391.       TmpArray[Y] |= (1 << X);
  392.       theGadget = theGadget->NextGadget;
  393.    }
  394.    Permit();
  395. }
  396.